#pragma once

#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include<filesystem>
#include<fstream>
#include <jsoncpp/json/json.h>
#include <mysql/mysql.h>

#include "log.hpp"

namespace ns_util
{

    // 对于Json库的简单封装，便于对数据进行序列化和反序列化
    class json_util
    {
    public:
        // 序列化
        static bool json_serialize(const Json::Value &root, std::string *str)
        {
            Json::StreamWriterBuilder swb;
            swb["emitUTF8"]=true;

            // Json::StreamWriter* sw=swb.newStreamWriter();

            // 使用智能指针
            std::unique_ptr<Json::StreamWriter> sw(swb.newStreamWriter());
            std::stringstream ss;

            int ret = sw->write(root, &ss);

            if (0 != ret)
            {
                LOG_ERR("%s", "json write error");
                return false;
            }

            *str = ss.str();

            return true;
        }

        // 反序列化
        static bool json_unserialize(Json::Value *root, const std::string &str)
        {
            Json::CharReaderBuilder cr;

            std::unique_ptr<Json::CharReader> cre(cr.newCharReader());

            bool ret = cre->parse(&str[0], &str[0] + str.size(), root, nullptr);

            if (false == ret)
            {
                LOG_ERR("%s", "json parse error");
                return false;
            }

            return true;
        }
    };

    // 对mysql函数进行封装，使其便于创建和连接，同时使之后的增加删除操作更加方便
    class mysql_util
    {

    public:
        // mysql的创建与连接
        static MYSQL *mysql_creat(const std::string &host, const std::string &user, const std::string &password, const std::string &name, uint16_t port)
        {
            MYSQL *mysql = mysql_init(NULL);

            if (NULL == mysql)
            {
                LOG_ERR("Init mysql instance failed");
                return NULL;
            }

            // 连接mysql服务
            MYSQL *sql_connect = mysql_real_connect(mysql, host.c_str(), user.c_str(), password.c_str(), name.c_str(), port, nullptr, 0);

            if (NULL == sql_connect)
            {
                LOG_ERR("connect mysql failed");

                mysql_close(mysql);

                return NULL;
            }

            // 设置字符集

            int ret = mysql_set_character_set(mysql, "utf8");

            if (ret != 0)
            {
                LOG_DBG("mysql character set error");
            }

            return mysql;
        }

        // 关闭mysql
        static void mysql_release(MYSQL *mysql)
        {
            if (nullptr != mysql)
            {
                mysql_close(mysql);
            }
            return;
        }

        // 执行sql语句

        static bool mysql_exec(MYSQL *mysql, const std::string &sql)
        {
            if (mysql_query(mysql, sql.c_str()) != 0)
            {
                LOG_ERR("SQL: %s", sql.c_str());
                LOG_ERR("ERR: %s", mysql_error(mysql));
                return false;
            }

            return true;
        }
    };

    // 对于分割字符串的实现，这里也可以用boost库中的分割函数
    class string_util
    {
    public:
        // 这里也可以在函数中设置一个标记位，用于选择是否对分割出的空字符串进行保存
        static int split(const std::string &in, const std::string &sep, std::vector<std::string> &arry)
        {
            arry.clear();

            // 当前分割的字符
            int index = 0;

            while (index < in.size())
            {
                int pos = in.find(sep, index);

                if (pos == std::string::npos)
                {
                    arry.push_back(in.substr(index));
                    return arry.size();
                }

                if(pos!=index)
                arry.push_back(in.substr(index,pos-index));

                index=pos+sep.size();
            }

            return arry.size();
        }


    };



    class file_util{
        public:

        static bool read(const std::string &filename,std::string* body)
        {
            std::ifstream file;

            file.open(filename.c_str(),std::ios::binary|std::ios::in);

            if(!file)
            {
                std::cout<<"open "<<filename<<" error"<<std::endl;
                return false;
            }

            //确定文件数据大小

            //将数据位定位到文件结尾
            file.seekg(0,std::ios::end);

            //计算数据位到文件开始的长度
            body->resize(file.tellg());

            file.seekg(0,std::ios::beg);

            file.read(&((*body)[0]),body->size());

            if(file.good()==false)
            {
                std::cout<<filename<<" read file error"<<std::endl;
                file.close();
                return false;
            }

            file.close();

            return true;
        }


    };


}